package learn.io.nio.client;

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Set;

public class ChatClient {

    private static final String DEFAULT_SERVER_HOST = "127.0.0.1";
    private static final int DEFAULT_SERVER_PORT = 8888;
    private static final String QUIT = "quit";
    private static final int BUFFER = 1024;

    private String host;
    private int port;
    private SocketChannel client;
    private ByteBuffer rBuffer = ByteBuffer.allocate(BUFFER);
    private ByteBuffer wBuffer = ByteBuffer.allocate(BUFFER);
    private Selector selector;
    private Charset charset = Charset.forName("UTF-8");


    public ChatClient() {
        this(DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT);
    }

    public ChatClient(String host, int port) {
        this.host = host;
        this.port = port;
    }
    public boolean readyToQuit(String msg) {
        return QUIT.equals(msg);
    }

    private void close(Closeable closable) {
        if (closable != null) {
            try {
                closable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    void start() throws IOException {
        client = SocketChannel.open();
        client.configureBlocking(false);

        selector = Selector.open();

        // 把自己在selector上注册一个CONNECT事件
        client.register(selector, SelectionKey.OP_CONNECT);
        client.connect(new InetSocketAddress(host, port));

        while (true) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectionKey : selectionKeys) {
                handles(selectionKey);
            }
            selectionKeys.clear();
        }
    }

    private void handles(SelectionKey key) throws IOException {
        if (key.isConnectable()) {
            // CONNECT事件
            
            SocketChannel client = (SocketChannel) key.channel();
            // 连接已经等待建立
            if (client.isConnectionPending()) {
                // 正式建立连接
                client.finishConnect();
                System.out.println("已连接服务器");
                // 处理用户输入
                new Thread(new UserInputHandler(this)).start();
            }
            client.register(selector, SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            // READ事件, 无服务器转发消息

            SocketChannel client = (SocketChannel) key.channel();
            String msg = recieve(client);
            if (msg.isEmpty()) {
                // 服务器异常
                close(selector);
            } else {
                System.out.println(msg);
            }
        }
    }

    private String recieve(SocketChannel client) throws IOException {
        rBuffer.clear();
        while (client.read(rBuffer) > 0);
        rBuffer.flip();
        return String.valueOf(charset.decode(rBuffer));
    }

    public void send(String msg) throws IOException {
        if (msg.isEmpty()) {
            return;
        }
        wBuffer.clear();
        wBuffer.put(charset.encode(msg));
        wBuffer.flip();
        while (wBuffer.hasRemaining()) {
            client.write(wBuffer);
        }
    }


    public static void main(String[] args) throws IOException {
        ChatClient client = new ChatClient("127.0.0.1", 7777);
        client.start();
    }
}
